# -*- encoding: utf-8 -*-
import psycopg2
import requests
import simplejson
from datetime import datetime, timedelta
import logging
import time
import argparse
import contextlib
import sys
import md5

logging.basicConfig(format='%(asctime)-15s %(levelname)-8s: %(message)s')
logger = logging.getLogger('GPS_Position')
logger.setLevel(logging.INFO)


class GPS_Position(object):
    _MAP_KEY = [
        'Vehicle', 'GPSTime', 'Speed',
        'Odometer', 'Lat', 'Lon',
        'Direction', 'Status', 'PlaceName',
    ]

    def __init__(self, database, user, password, host, port, gps_login, gps_password, sleep):
        try:
            self.conn = psycopg2.connect(database=database, user=user,
                                     password=password, host=host, port=port)
        except psycopg2.Error as e:
            logger.error(u'数据库连接失败:%s' % e)
            sys.exit(1)

        self.sleep_time = sleep
        self.vehicles = {}
        self.url = 'http://61.129.66.212/rest/interface/monitorAll/{login}/{password}'.format(
            login=gps_login,
            password=md5.md5(gps_password).hexdigest(),
        )

    def _get_gps_records(self):
        res = []
        try:
            response = requests.get(self.url)
        except requests.exceptions.RequestException as e:
            logger.error(u'连接GPS平台错误%s' % e)
            logger.info(u'%sS后再次尝试连接GPS平台' % self.sleep_time)
            time.sleep(self.sleep_time)
            return self._get_gps_records()

        try:
            content = simplejson.loads(response.content)
        except Exception as e:
            logger.error(u'解析错误:' + response.content.decode('utf-8'))
            logger.info(u'%sS后再次尝试连接GPS平台' % self.sleep_time)
            time.sleep(self.sleep_time)
            return self._get_gps_records()

        records = content.get('NewDataSet', [])
        for record in records:
            res.append({key.lower(): value for key, value in \
                      record.iteritems() if key in self._MAP_KEY})

        return res

    def _is_parking(self, record):
        vehicle = self.vehicles.get(record.get('vehicle'))
        if vehicle and vehicle.get('speed') == 0 and \
            vehicle.get('lat') == record.get('lat') and \
                vehicle.get('lon') == vehicle.get('lon'):

            return True

        return False

    def _update_last_vehicles(self, record):
        if not self.vehicles.get(record.get('vehicle')):
            self.vehicles[record.get('vehicle')] = {}

        self.vehicles[record.get('vehicle')].update({
            'speed': record.get('speed'),
            'lat': record.get('lat'),
            'lon': record.get('lon'),
            'waiting_time': datetime.now(),
        })

    def _get_waiting_time(self, record):
        vehicle = self.vehicles.get(record.get('vehicle'))
        return datetime.now() - vehicle.get('waiting_time')

    def _update_parking_info(self, cr, record):
        waiting_time = self._get_waiting_time(record)

        cr.execute('''
            UPDATE gps_position set waiting_time = %s
            WHERE ID = (SELECT MAX(id) FROM gps_position WHERE vehicle = %s)
        ''', (waiting_time.seconds, record.get('vehicle')))

        self.conn.commit()

    def _create_position(self, cr, record):
        self._update_last_vehicles(record)

        encode_record = {}
        for key, value in record.iteritems():
            encode_record[key] = isinstance(value, basestring) and value.encode('utf-8') or value

        encode_record.update({
            'create_uid': 1,
            'write_uid': 1,
        })

        cr.execute('''
            INSERT INTO gps_position (create_date, create_uid, write_date,
                                      write_uid, vehicle, gpstime, speed,
                                      odometer, lat, lon, direction, status,
                                      placename)
            VALUES (%s, {create_uid}, %s, {write_uid},
                    '{vehicle}', %s, {speed}, {odometer}, {lat}, {lon},
                    {direction}, '{status}', '{placename}')
        '''.format(**encode_record), (
            datetime.utcnow(), datetime.utcnow(),
            datetime.strptime(encode_record.get('gpstime'), '%Y-%m-%d %H:%M:%S') - timedelta(hours=8)
        ))

        logger.info(u'%s 创建新的地址记录（%s-%s)' % (record.get('vehicle'), record.get('lat'), record.get('lon')))
        self.conn.commit()

    def start(self):
        with contextlib.closing(self.conn.cursor()) as cr:
            while True:
                records = self._get_gps_records()
                for record in records:
                    if self._is_parking(record):
                        self._update_parking_info(cr, record)
                    else:
                        self._create_position(cr, record)

                time.sleep(self.sleep_time)

if __name__ == '__main__':
    logger.info('Start')

    parser = argparse.ArgumentParser(description=u'使用捷依GPS平台获取的位置信息更新数据库')
    parser.add_argument('-d', '--database', dest="database", help=u'指定数据库', required=True)
    parser.add_argument('-u', '--user', dest='user', help=u'指定数据库用户', default='root')
    parser.add_argument('-pd', '--password', dest='password', help=u'数据库登录密码', default=False)
    parser.add_argument('-ht', '--host', dest='host', help=u'指定数据库的地址', default='localhost')
    parser.add_argument('-p', '--port', dest='port', help=u'指定数据库的端口', default=5432, type=int)
    parser.add_argument('-login', dest='login', help=u'捷依GPS平台帐号', default='shhzsy')
    parser.add_argument('-passwd', dest='gps_password', help=u'捷依GPS平台密码', default='123456')
    parser.add_argument('-s', '--sleep', dest='sleep', help=u'指定每次获取平台GPS地理信息的时间间隔', default=30, type=int)

    args = parser.parse_args()
    GPS_Position(database=args.database,
                 user=args.user,
                 password=args.password,
                 host=args.host,
                 port=args.port,
                 gps_login=args.login,
                 gps_password=args.gps_password,
                 sleep=args.sleep).start()
